package com.lagou.edu.factory;


import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import com.mysql.cj.util.StringUtils;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 用于发现@Service注解，并生成Bean放入map中
 */
public class AnnotationBeanFactory {
    private static Map<String, Object> map = new HashMap<>();

    static {
        // 扫描com.lagou.edu下所有的类
        Reflections reflections = new Reflections("com.lagou.edu");
        // 找到有@Service注解标注的所有类
        Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(Service.class);
        try {
            for (Class<?> aClass : typesAnnotatedWith) {
                Object object = aClass.newInstance();
                Service serviceAnnotation = aClass.getAnnotation(Service.class);
                // 判断是否使用了value属性
                if (StringUtils.isNullOrEmpty(serviceAnnotation.value())) {
                    String className = aClass.getName();
                    map.put(className.substring(className.lastIndexOf(".") + 1), object);
                } else {
                    map.put(serviceAnnotation.value(), object);
                }
            }

            // 只有实例化完成后才能后进行@Autowired注入
            // 遍历map中的bean找到@Autowired标注的bean，并用set注入
            for (Map.Entry<String, Object> a : map.entrySet()) {
                Object o = a.getValue();
                Class c = o.getClass();
                Field[] fields = c.getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Autowired.class) && field.getAnnotation(Autowired.class).required()) {
                        String className = field.getType().getName().substring(field.getType().getName().lastIndexOf(".") + 1);
                        Method[] methods = c.getMethods();
                        for (int j = 0; j < methods.length; j++) {
                            Method method = methods[j];
                            if (method.getName().equalsIgnoreCase("set" + className)) {  // 该方法就是 setAccountDao(AccountDao accountDao)
                                method.invoke(o, map.get(className));
                            }
                        }
                    }
                }

                // 判断是否有@TranTransactional注解标注
                if (c.isAnnotationPresent(Transactional.class)) {
                    //获取代理工厂
                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                    Class[] interfaces = c.getInterfaces();//获取类c实现的所有接口
                    //判断对象是否实现接口
                    if (interfaces != null && interfaces.length > 0) {
                        //实现使用JDK
                        o = proxyFactory.getJdkProxy(o);
                    } else {
                        //没实现使用CGLIB
                        o = proxyFactory.getCglibProxy(o);
                    }
                }
                map.put(a.getKey(), o);
            }


            System.out.println("封装完毕");
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public static Object getBean(String id) {
        return map.get(id);
    }
}
